package cn.turboinfo.fuyang.api.gateway.mini.framework.http.interceptor;

import cn.turboinfo.fuyang.api.domain.common.usecase.user.CommonListUserTypeUseCase;
import cn.turboinfo.fuyang.api.domain.mini.usecase.login.MiniValidateAndRefreshSessionUseCase;
import cn.turboinfo.fuyang.api.domain.mini.usecase.user.MiniGetUserInfoUseCase;
import cn.turboinfo.fuyang.api.entity.common.pojo.user.SysUser;
import cn.turboinfo.fuyang.api.entity.common.pojo.user.UserTypeRel;
import cn.turboinfo.fuyang.api.entity.mini.exception.session.MiniSessionNotFoundException;
import cn.turboinfo.fuyang.api.entity.mini.pojo.session.MiniSession;
import cn.turboinfo.fuyang.api.gateway.mini.constant.MiniRestConstants;
import cn.turboinfo.fuyang.api.gateway.mini.framework.http.context.MiniRequestContext;
import cn.turboinfo.fuyang.api.gateway.mini.framework.http.context.MiniRequestContextHolder;
import cn.turboinfo.fuyang.api.gateway.web.framework.http.annotation.SessionScope;
import cn.turboinfo.fuyang.api.gateway.web.framework.http.interceptor.BaseHandlerInterceptorAdapter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import nxcloud.ext.springmvc.automapping.spring.AutoMappingRequestParameterTypeBinding;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Optional;

@Slf4j
@RequiredArgsConstructor
@Component
public class MiniSessionScopeInterceptor extends BaseHandlerInterceptorAdapter {

    private final MiniValidateAndRefreshSessionUseCase validateAndRefreshSessionUseCase;

    private final MiniGetUserInfoUseCase getUserInfoUseCase;

    private final CommonListUserTypeUseCase listUserTypeUseCase;

    private final AutoMappingRequestParameterTypeBinding autoMappingRequestParameterTypeBinding;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;

            Optional<SessionScope> sessionScopeOptional = getAnnotation(handlerMethod, SessionScope.class, true);

            SessionScope sessionScope = sessionScopeOptional.orElseGet(() -> autoMappingRequestParameterTypeBinding.getAnnotation(handlerMethod.getMethod(), SessionScope.class, true));

            if (sessionScope != null) {
                boolean throwException = sessionScope.throwException();

                // 获取 token
                String sessionToken = request.getHeader(MiniRestConstants.HEADER_SESSION_TOKEN);
                if (StringUtils.isBlank(sessionToken)) {
                    if (throwException) {
                        throw new MiniSessionNotFoundException("未指定会话令牌");
                    }
                    return true;
                }

                // 验证并续期会话
                MiniSession session;
                try {
                    session = validateAndRefreshSessionUseCase.execute(MiniValidateAndRefreshSessionUseCase.InputData
                            .builder()
                            .token(sessionToken)
                            .build()).getSession();
                } catch (MiniSessionNotFoundException e) {
                    if (throwException) {
                        throw e;
                    }
                    return true;
                }

                // 列表用户类型供后续使用
                List<UserTypeRel> userTypeRelList = listUserTypeUseCase.execute(CommonListUserTypeUseCase.InputData
                        .builder()
                        .userId(session.getUserId())
                        .build()).getUserTypeRelList();

                // 获取用户信息
                SysUser sysUser = getUserInfoUseCase.execute(MiniGetUserInfoUseCase
                        .InputData
                        .builder()
                        .userId(session.getUserId())
                        .build()).getUserInfo();

                // 保存信息到 context
                MiniRequestContext requestContext = MiniRequestContextHolder.current();
                requestContext.setUserId(session.getUserId());
                requestContext.setSession(session);
                requestContext.setUserTypeRelList(userTypeRelList);
                requestContext.setUser(sysUser);
            }
        }
        return true;
    }

}
